#ifndef RTPPARSE_RTPSTREAM_H
#define RTPPARSE_RTP_LISTENER_H

#include <cstdint>
#include <string>
#include <vector>
#include "rtp/RtpDictionaries.h"


namespace Rtp {
    class RtpPacket;
    class RtxStream;
    class RtpStream {
    protected:
        class Listener {
        public:
            virtual ~Listener() = default;
        public:
            virtual void OnRtpStreamScore(Rtp::RtpStream *rtpStream, uint8_t score, uint8_t previousScore) = 0;
        };
    public:
        struct Params {
            size_t encodingIdx{ 0u };
			uint32_t ssrc{ 0u };
			uint8_t payloadType{ 0u };
			Rtp::RtpCodecMimeType mimeType;
			uint32_t clockRate{ 0u };
			std::string rid;
			std::string cname;
			uint32_t rtxSsrc{ 0u };
			uint8_t rtxPayloadType{ 0u };
			bool useNack{ false };
			bool usePli{ false };
			bool useFir{ false };
			bool useInBandFec{ false };
			bool useDtx{ false };
			uint8_t spatialLayers{ 1u };
			uint8_t temporalLayers{ 1u };
        };

    public:
        RtpStream(Rtp::RtpStream::Listener *listener, Rtp::RtpStream::Params& params, uint8_t initialScore);
        virtual ~RtpStream();

        uint32_t GetEncodingIdx() const {
            return this->params.encodingIdx;
        }

        uint32_t GetSsrc() const {
            return this->params.ssrc;
        }

        uint8_t GetPayloadType() const {
			return this->params.payloadType;
		}

        const Rtp::RtpCodecMimeType& GetMimeType() const {
            return this->params.mimeType;
        }

        uint32_t GetClockRate() const {
            return this->params.clockRate;
        }

        const std::string& GetRid() const {
            return this->params.rid;
        }

        const std::string& GetCname() const {
            return this->params.cname;
        }

        bool HasRtx() const {
            return this->rtxStream == nullptr;
        }

        virtual void SetRtx(uint8_t payloadType, uint32_t ssrc);

        uint32_t GetRtxSsrc() const {
            return this->params.rtxSsrc;
        }

        uint8_t GetRtxPayloadType() const {
            return this->params.rtxPayloadType;
        }

        uint8_t GetSpatialLayers() const {
            return this->params.spatialLayers;
        }

        bool HasDtx() const {
            return this->params.useDtx;
        }

        uint8_t GetTemporalLayers() const {
            return this->params.temporalLayers;
        }

        virtual bool ReceiveStreamPacket(Rtp::RtpPacket *packet);
        virtual void Pause();
        virtual void Resume();
        void ResetScore(uint8_t score, bool notify);
    protected:
        bool UpdateSeq(Rtp::RtpPacket *packet);
        void PacketRetransmitted(Rtp::RtpPacket* packet);
		void PacketRepaired(Rtp::RtpPacket* packet);
    private:
		void InitSeq(uint16_t seq);
    protected:
		virtual void UserOnSequenceNumberReset() = 0;
    protected:
        Rtp::RtpStream::Listener *listener { nullptr };

        Params params;

        uint16_t maxSeq{ 0u };
		// Shifted count of seq. number cycles.
		uint32_t cycles{ 0u };
		// Base seq number.
		uint32_t baseSeq{ 0u };
		// Last 'bad' seq number + 1.
		uint32_t badSeq{ 0u };
		// Highest timestamp seen.
		uint32_t maxPacketTs{ 0u };
		// When the packet with highest timestammp was seen.
		uint64_t maxPacketMs{ 0u };
		uint32_t packetsLost{ 0u };
		uint8_t fractionLost{ 0u };
		size_t packetsDiscarded{ 0u };
		size_t packetsRetransmitted{ 0u };
		size_t packetsRepaired{ 0u };
		size_t nackCount{ 0u };
		size_t nackPacketCount{ 0u };
		size_t pliCount{ 0u };
		size_t firCount{ 0u };
		// Packets repaired at last interval for score calculation.
		size_t repairedPriorScore{ 0u };
		// Packets retransmitted at last interval for score calculation.
		size_t retransmittedPriorScore{ 0u };
		// NTP timestamp in last Sender Report (in ms).
		uint64_t lastSenderReportNtpMs{ 0u };
		// RTP timestamp in last Sender Report.
		uint32_t lastSenderReportTs{ 0u };
		float rtt{ 0.0f };
        Rtp::RtxStream *rtxStream { nullptr };
    private:
		// Score related.
		uint8_t score{ 0u };
		std::vector<uint8_t> scores;
		// Whether at least a RTP packet has been received.
		bool started{ false };
		// Last time since the stream is active.
		uint64_t activeSinceMs{ 0u };
    };
}

#endif